package com.ruoyi.security.filter;

import com.ruoyi.common.constant.CacheConstants;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.utils.CacheUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.ServletUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.web.service.TokenService;
import eu.bitwalker.useragentutils.Browser;
import eu.bitwalker.useragentutils.OperatingSystem;
import eu.bitwalker.useragentutils.UserAgent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Enumeration;

/**
 * token过滤器 验证token有效性
 *
 * @author ruoyi
 */
@Component
@Slf4j
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
    @Autowired
    private TokenService tokenService;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
            throws ServletException, IOException {
        //判断当前请求是否是通过移动设备上发出的，如微信小程序等。
        boolean isMobileDevice = ServletUtils.isMobileDevice(request);
        //判断当前的请求是否来自微信小程序调试工具
        boolean isMiniprogramWxDevTool = ServletUtils.isMiniprogramWxDevTool(request);

        LoginUser loginUser;
        if (isMobileDevice || isMiniprogramWxDevTool) { //MOBILE：手机端，如微信小程序等。
            loginUser = tokenService.getMiniprogramLoginUser(request);

            if (StringUtils.isNotNull(loginUser)) {
                String token = loginUser.getToken();
                long expireTime = CacheUtils.getExpire(CacheConstants.LOGIN_TOKEN_KEY_MINI, token);
                log.info("doFilterInternal expireTime: {}", expireTime);
            }
        } else {
            loginUser = tokenService.getLoginUser(request);
        }

        if (StringUtils.isNotNull(loginUser) && StringUtils.isNull(SecurityUtils.getAuthentication())) {
            tokenService.verifyToken(loginUser);
            UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginUser, null, loginUser.getAuthorities());
            authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
            SecurityContextHolder.getContext().setAuthentication(authenticationToken);
        }
        chain.doFilter(request, response);
    }

    //测试方法
    private void test(HttpServletRequest request) {
        Enumeration<String> headerNames = request.getHeaderNames();
        while (headerNames.hasMoreElements()) {
            String headerName = headerNames.nextElement();
            log.info("doFilterInternal header: {} ---> {}", headerName, request.getHeader(headerName));
        }

        String agent = request.getHeader("User-Agent"); //示例："Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.81 Safari/537.36"

        //解析agent字符串
        UserAgent userAgent = UserAgent.parseUserAgentString(agent);
        //获取浏览器对象
        Browser browser = userAgent.getBrowser();
        //获取操作系统对象
        OperatingSystem operatingSystem = userAgent.getOperatingSystem();

        log.info("浏览器名: {}", browser.getName());
        log.info("浏览器类型: {}", browser.getBrowserType());
        log.info("浏览器家族: {}", browser.getGroup());
        log.info("浏览器生产厂商: {}", browser.getManufacturer());
        log.info("浏览器使用的渲染引擎: {}", browser.getRenderingEngine());
        log.info("浏览器版本: {}", userAgent.getBrowserVersion());

        log.info("操作系统名: {}", operatingSystem.getName());
        log.info("访问设备类型: {}", operatingSystem.getDeviceType()); // 可能取值：COMPUTER：电脑浏览器，MOBILE：手机端，如微信小程序等。
        log.info("操作系统家族: {}", operatingSystem.getGroup());
        log.info("操作系统生产厂商: {}", operatingSystem.getManufacturer());

    }
}
